﻿using System.Collections.Generic;
using Bridge.Base.Converter;
using Pathfinder.Base.Constructs;
using Pathfinder.Base.Utilities;

namespace Pathfinder.Base.Importer
{
    public abstract class PFStatblockImporter : StatblockConverter<PathfinderCharacter>
    {
        public override PathfinderCharacter Convert(string input)
        {
            string name = GetName(input);
            string cr = GetCR(input);
            string sa = GetSA(input);
            string sq = GetSQ(input);
            string aura = GetAura(input);
            string spellLikeAbilities = GetSpellLikeAbilities(input);
            string defensiveAbilities = GetDefensiveAbilities(input);

            int baseHP = GetBaseHP(input);
            int currentHP = GetCurrentHP(input);
            int maxHP = GetMaxHP(input);
            int sr = GetSR(input);
            int bonusHP = GetBonusHP(input);
            int space = GetSpace(input);
            int reach = GetReach(input);
            int bab = GetBAB(input);

            Dictionary<ACType, int> acs = GetAC(input);
            Dictionary<SaveType, int> baseSaves = GetBaseSaves(input);
            Dictionary<SaveType, int> saves = GetSaves(input);
            Dictionary<DRType, int> drs = GetDR(input);
            Dictionary<ERType, int> ers = GetER(input);
            Dictionary<int, int> hds = GetHD(input);
            Dictionary<SightType, int> sights = GetSights(input);
            Dictionary<SpeedType, int> speeds = GetSpeeds(input);
            Dictionary<StatType, int> stats = GetStats(input);
            Dictionary<StatType, int> baseStats = GetBaseStats(input);

            int initiativeBonus = GetInitiativeBonus(input, stats[StatType.Dexterity].GetBonus());
            baseSaves[SaveType.Fort] -= baseStats[StatType.Constitution].GetBonus();
            baseSaves[SaveType.Ref] -= baseStats[StatType.Dexterity].GetBonus();
            baseSaves[SaveType.Will] -= baseStats[StatType.Wisdom].GetBonus();

            saves[SaveType.Fort] -= stats[StatType.Constitution].GetBonus();
            saves[SaveType.Ref] -= stats[StatType.Dexterity].GetBonus();
            saves[SaveType.Will] -= stats[StatType.Wisdom].GetBonus();

            List<string> feats = GetFeats(input);
            IEnumerable<SubType> subTypes = GetSubTypes(input);
            IEnumerable<ImmunityType> immunityTypes = GetImmunityTypes(input);

            FlyManuverability flyManuverability = GetFlyManuverability(input);
            CreatureType creatureType = GetCreatureType(input);
            SizeType sizeType = GetSizeType(input);
            Alignment alignment = GetAlignment(input);

            PathfinderCharacter character = new PathfinderCharacter();

            foreach (KeyValuePair<ACType, int> ac in acs)
            {
                character.AddAC(ac.Key, ac.Value);
            }
            foreach (KeyValuePair<StatType, int> stat in baseStats)
            {
                character.AddBaseStat(stat.Key, stat.Value);
            }
            foreach (KeyValuePair<DRType, int> dr in drs)
            {
                character.AddDR(dr.Key, dr.Value);
            }
            foreach (KeyValuePair<ERType, int> er in ers)
            {
                character.AddER(er.Key, er.Value);
            }
            foreach (string feat in feats)
            {
                character.AddFeat(new Feat(feat));
            }
            foreach (KeyValuePair<int, int> hd in hds)
            {
                character.AddHitDice(hd.Key, hd.Value);
            }
            foreach (KeyValuePair<SightType, int> sight in sights)
            {
                character.AddSight(sight.Key, sight.Value);
            }
            foreach (KeyValuePair<SpeedType, int> speed in speeds)
            {
                character.AddSpeed(speed.Key, speed.Value);
            }
            foreach (SubType subType in subTypes)
            {
                character.AddSubType(subType);
            }
            foreach (KeyValuePair<StatType, int> stat in stats)
            {
                character.SetTotalStat(stat.Key, stat.Value);
            }
            foreach (KeyValuePair<StatType, int> stat in baseStats)
            {
                character.SetBaseStat(stat.Key, stat.Value);
            }
            foreach (KeyValuePair<SaveType, int> save in saves)
            {
                character.SetSave(save.Key, save.Value);
            }
            foreach (KeyValuePair<SaveType, int> save in baseSaves)
            {
                character.SetBaseSave(save.Key, save.Value);
            }
            foreach (ImmunityType immunity in immunityTypes)
            {
                character.AddImmunity(immunity);
            }
            character.Alignment = alignment;
            character.Aura = aura;
            character.BAB = bab;
            character.BaseHP = baseHP;
            character.BonusHP = bonusHP;
            character.CR = cr;
            character.CreatureType = creatureType;
            character.CurrentHitPoints = currentHP;
            character.DefensiveAbilities = defensiveAbilities;
            character.FlyManuverability = flyManuverability;
            character.InitBonus = initiativeBonus;
            character.MaximumHitPoints = maxHP;
            character.Name = name;
            character.Reach = reach;
            character.Size = sizeType;
            character.Space = space;
            character.SpecialAttacks = sa;
            character.SpecialQualities = sq;
            character.SpellLikeAbilities = spellLikeAbilities;
            character.SR = sr;
            character.Statblock = input;

            foreach (Skill skill in GetSkills(input, character))
            {
                character.SetSkill(skill);
            }

            foreach (Attack attack in GetAttacks(input, character))
            {
                character.AddAttack(attack);
            }

            return character;
        }

        public virtual string GetName(string input)
        {
            return MainStatblockImporter.FindName(input) ?? string.Empty;
        }

        public virtual string GetCR(string input)
        {
            return MainStatblockImporter.FindCR(input) ?? string.Empty;
        }

        public virtual string GetSA(string input)
        {
            return OffenseStatblockImporter.FindSpecialAttacks(input) ?? string.Empty;
        }

        public virtual string GetSQ(string input)
        {
            return StatisticsStatblockImporter.FindSpecialQualities(input) ?? string.Empty;
        }

        public virtual string GetAura(string input)
        {
            return MainStatblockImporter.FindAura(input) ?? string.Empty;
        }

        public virtual string GetSpellLikeAbilities(string input)
        {
            return OffenseStatblockImporter.FindSpellLikeAbilities(input) ?? string.Empty;
        }

        public virtual string GetDefensiveAbilities(string input)
        {
            return DefenseStatblockImporter.FindDefensiveAbilities(input) ?? string.Empty;
        }

        public virtual int GetBaseHP(string input)
        {
            return DefenseStatblockImporter.FindBaseHP(input) ?? 0;
        }

        public virtual int GetCurrentHP(string input)
        {
            return DefenseStatblockImporter.FindCurrentHP(input) ?? 0;
        }

        public virtual int GetMaxHP(string input)
        {
            return DefenseStatblockImporter.FindMaxHP(input) ?? 0;
        }

        public virtual int GetSR(string input)
        {
            return DefenseStatblockImporter.FindSR(input) ?? 0;
        }

        public virtual int GetBonusHP(string input)
        {
            return DefenseStatblockImporter.FindBonusHP(input) ?? 0;
        }

        public virtual int GetSpace(string input)
        {
            return OffenseStatblockImporter.FindSpace(input);
        }

        public virtual int GetReach(string input)
        {
            return OffenseStatblockImporter.FindReach(input);
        }

        public virtual int GetBAB(string input)
        {
            return StatisticsStatblockImporter.FindBAB(input) ?? 0;
        }

        public virtual Dictionary<ACType, int> GetAC(string input)
        {
            return DefenseStatblockImporter.FindAC(input) ?? new Dictionary<ACType, int>();
        }

        public virtual Dictionary<SaveType, int> GetSaves(string input)
        {
            return DefenseStatblockImporter.FindSaves(input, false);
        }

        public virtual Dictionary<SaveType, int> GetBaseSaves(string input)
        {
            return DefenseStatblockImporter.FindSaves(input, true);
        }

        public virtual Dictionary<DRType, int> GetDR(string input)
        {
            return DefenseStatblockImporter.FindDR(input) ?? new Dictionary<DRType, int>();
        }

        public virtual Dictionary<ERType, int> GetER(string input)
        {
            return DefenseStatblockImporter.FindER(input) ?? new Dictionary<ERType, int>();
        }

        public virtual Dictionary<int, int> GetHD(string input)
        {
            return DefenseStatblockImporter.FindHD(input) ?? new Dictionary<int, int>();
        }

        public virtual Dictionary<SightType, int> GetSights(string input)
        {
            return MainStatblockImporter.FindSight(input) ?? new Dictionary<SightType, int>();
        }

        public virtual Dictionary<SpeedType, int> GetSpeeds(string input)
        {
            return OffenseStatblockImporter.FindSpeeds(input);
        }

        public virtual Dictionary<StatType, int> GetStats(string input)
        {
            return StatisticsStatblockImporter.FindStats(input, false);
        }

        public virtual Dictionary<StatType, int> GetBaseStats(string input)
        {
            return StatisticsStatblockImporter.FindStats(input, true);
        }

        public virtual int GetInitiativeBonus(string input, int dexBonus)
        {
            int totalInitiative = MainStatblockImporter.FindInitiative(input) ?? dexBonus;
            return totalInitiative -= dexBonus;
        }

        public virtual List<string> GetFeats(string input)
        {
            return StatisticsStatblockImporter.FindFeats(input) ?? new List<string>();
        }

        public virtual IEnumerable<SubType> GetSubTypes(string input)
        {
            return MainStatblockImporter.FindSubTypes(input) ?? new List<SubType>();
        }

        public virtual IEnumerable<ImmunityType> GetImmunityTypes(string input)
        {
            return DefenseStatblockImporter.FindImmunities(input) ?? new List<ImmunityType>();
        }

        public virtual FlyManuverability GetFlyManuverability(string input)
        {
            return OffenseStatblockImporter.FindFlyManuverability(input);
        }

        public virtual CreatureType GetCreatureType(string input)
        {
            return MainStatblockImporter.FindCreatureType(input) ?? CreatureType.Humanoid;
        }

        public virtual SizeType GetSizeType(string input)
        {
            return MainStatblockImporter.FindSize(input) ?? SizeType.Medium;
        }

        public virtual Alignment GetAlignment(string input)
        {
            return MainStatblockImporter.FindAlignment(input) ?? Alignment.TrueNeutral;
        }

        public virtual List<Skill> GetSkills(string input, PathfinderCharacter character)
        {
            IEnumerable<string> skillStrings = GetSkillList(input);
            List<Skill> skills = new List<Skill>();
            foreach (string skill in skillStrings)
            {
                Skill skillFound = GetSkill(skill, character);
                if (skillFound != null)
                {
                    skills.Add(skillFound);
                }
            }
            return skills;
        }

        public virtual IEnumerable<string> GetSkillList(string input)
        {
            return StatisticsStatblockImporter.FindSkills(input) ?? new List<string>();
        }

        public virtual Skill GetSkill(string input, PathfinderCharacter character)
        {
            return StatisticsStatblockImporter.FindSkill(input, character);
        }

        public virtual IEnumerable<Attack> GetAttacks(string input, PathfinderCharacter character)
        {
            IEnumerable<string> meleeAttacks = GetAttackList(input, true);
            List<Attack> attacks = new List<Attack>();
            if (meleeAttacks != null)
            {
                foreach (string attack in meleeAttacks)
                {
                    Attack attackFound = GetAttack(attack, true, character);
                    if (attackFound != null)
                    {
                        attacks.Add(attackFound);
                    }
                }
            }
            IEnumerable<string> rangedAttacks = GetAttackList(input, false);
            if (rangedAttacks != null)
            {
                foreach (string attack in rangedAttacks)
                {
                    Attack attackFound = GetAttack(attack, false, character);
                    if (attackFound != null)
                    {
                        attacks.Add(attackFound);
                    }
                }
            }
            return attacks;
        }

        public virtual IEnumerable<string> GetAttackList(string input, bool isMelee)
        {
            return OffenseStatblockImporter.FindAttacks(input, isMelee);
        }

        public virtual Attack GetAttack(string input, bool isMelee, PathfinderCharacter character)
        {
            return OffenseStatblockImporter.FindAttack(input, !isMelee, character);
        }
    }
}
